use std::{collections::HashSet, fs, path::Path};

use clap::Parser;
use rand::Rng;
use tracing::{debug, error, info, warn};

static RESULT_DIR: &str = "./merit_result";

#[derive(Parser)]
#[command(version, author, about, long_about = None)]
struct Cli {
    /// user merit result file path, eg: /apple/q3/net_work/more.xls
    #[arg(short, long)]
    merit: String,

    /// user merit excel file sheet name.
    #[arg(short, long, default_value_t = String::from("季度绩效考核成绩汇总表 模板"))]
    a_sheet: String,

    /// your template file path, eg: /apple/q3/template.xlsx
    #[arg(short, long)]
    template: String,

    /// result template data write to sheet name.
    #[arg(short, long, default_value_t = String::from("绩效计划及评估表"))]
    b_sheet: String,

    /// 1 filld data, 0 is a empty template
    #[arg(short, long, default_value_t = 1)]
    empty: u8,

    /// base for merit data rand result, default rand data range [-3, 5]
    #[arg(short, long, default_value_t = 0)]
    rand: u8,
}

fn rand_edit_crate(args: &Cli, dir: &str) -> Result<(), Box<dyn std::error::Error>> {
    info!("2---");
    let mut rng = rand::thread_rng();

    let mut name_set = HashSet::new();
    let path = std::path::Path::new(&args.merit);
    let book = umya_spreadsheet::reader::xlsx::read(path)?;
    let sheet = book.get_sheet_by_name(&args.a_sheet).unwrap();

    for (key, _row) in sheet.get_row_dimensions_to_hashmap() {
        let nm = sheet.get_value((2, *key));
        let id = sheet.get_value_number((1, *key));
        if nm.is_empty() || id.is_none() {
            error!("id or name parse error: row number is {}", key);
            continue;
        }

        let id = id.unwrap();
        debug!("k -> {}, v -> {}", id, nm);

        let path = Path::new(&args.template);
        let mut book = umya_spreadsheet::reader::xlsx::read(path).unwrap();
        let worksheet = book.get_sheet_by_name_mut(&args.b_sheet).unwrap();

        let ti = sheet.get_value((7, *key));
        worksheet.get_cell_mut("L3").set_value(&ti);

        // set value
        worksheet.get_cell_mut("D3").set_value(&nm);
        worksheet.get_cell_mut("F3").set_value(id.to_string());
        let merit_1 = sheet.get_value((30, *key));
        worksheet.get_cell_mut("N3").set_value(merit_1);
        //worksheet.get_cell_mut("Q3").set_value(date);

        if args.empty == 1 {
            let merit_1 = sheet.get_value((33, *key));
            worksheet.get_cell_mut("P7").set_value(merit_1);

            let merit_1 = sheet.get_value_number((34, *key)).unwrap_or(0f64);
            worksheet.get_cell_mut("R7").set_value(merit_1.to_string());
            let random_int: i32 = rng.gen_range(-3..=3);
            let merit_1 = merit_1 - (random_int as f64);
            worksheet.get_cell_mut("N7").set_value(merit_1.to_string());

            let merit_1 = sheet.get_value((35, *key));
            worksheet.get_cell_mut("P8").set_value(merit_1);

            let merit_1 = sheet.get_value_number((36, *key)).unwrap_or(0f64);
            worksheet.get_cell_mut("R8").set_value(merit_1.to_string());
            let random_int: i32 = rng.gen_range(-3..=3);
            let merit_1 = merit_1 - (random_int as f64);
            worksheet.get_cell_mut("N8").set_value(merit_1.to_string());

            let merit_1 = sheet.get_value((37, *key));
            worksheet.get_cell_mut("P9").set_value(merit_1);

            let merit_1 = sheet.get_value_number((38, *key)).unwrap_or(0f64);
            worksheet.get_cell_mut("R9").set_value(merit_1.to_string());
            let random_int: i32 = rng.gen_range(-3..=3);
            let merit_1 = merit_1 - (random_int as f64);
            worksheet.get_cell_mut("N9").set_value(merit_1.to_string());

            let merit_1 = sheet.get_value((39, *key));
            worksheet.get_cell_mut("P10").set_value(merit_1);

            let merit_1 = sheet.get_value_number((40, *key)).unwrap_or(0f64);
            worksheet.get_cell_mut("R10").set_value(merit_1.to_string());
            let random_int: i32 = rng.gen_range(-3..=3);
            let merit_1 = merit_1 - (random_int as f64);
            worksheet.get_cell_mut("N10").set_value(merit_1.to_string());

            let merit_1 = sheet.get_value((41, *key));
            worksheet.get_cell_mut("P11").set_value(merit_1);

            let merit_1 = sheet.get_value_number((42, *key)).unwrap_or(0f64);
            worksheet.get_cell_mut("R11").set_value(merit_1.to_string());
            let random_int: i32 = rng.gen_range(-3..=3);
            let merit_1 = merit_1 - (random_int as f64);
            worksheet.get_cell_mut("N11").set_value(merit_1.to_string());

            let merit_1 = sheet.get_value((43, *key));
            worksheet.get_cell_mut("P12").set_value(merit_1);

            let merit_1 = sheet.get_value_number((44, *key)).unwrap_or(0f64);
            worksheet.get_cell_mut("R12").set_value(merit_1.to_string());
            let random_int: i32 = rng.gen_range(-5..=3);
            let merit_1 = merit_1 - (random_int as f64);
            worksheet.get_cell_mut("N12").set_value(merit_1.to_string());
        }

        // user self

        // writer
        let new_path = if name_set.contains(&nm) {
            format!("{}/{}-{}.xlsx", dir, nm, id)
        } else {
            name_set.insert(nm.clone());
            format!("{}/{}.xlsx", dir, nm)
        };
        info!("> --- {:?}", new_path);
        let path = std::path::Path::new(&new_path);
        let _ = umya_spreadsheet::writer::xlsx::write(&book, path);
    }
    Ok(())
}

fn edit_crate(args: &Cli, dir: &str) -> Result<(), Box<dyn std::error::Error>> {
    info!("1---");
    let mut name_set = HashSet::new();
    let path = std::path::Path::new(&args.merit);
    let book = umya_spreadsheet::reader::xlsx::read(path)?;
    let sheet = book.get_sheet_by_name(&args.a_sheet).unwrap();

    for (key, _row) in sheet.get_row_dimensions_to_hashmap() {
        let nm = sheet.get_value((2, *key));
        let id = sheet.get_value_number((1, *key));
        if nm.is_empty() || id.is_none() {
            error!("id or name parse error: row number is {}", key);
            continue;
        }

        let id = id.unwrap();
        debug!("k -> {}, v -> {}", id, nm);

        let path = Path::new(&args.template);
        let mut book = umya_spreadsheet::reader::xlsx::read(path).unwrap();
        let worksheet = book.get_sheet_by_name_mut(&args.b_sheet).unwrap();

        let ti = sheet.get_value((7, *key));
        worksheet.get_cell_mut("L3").set_value(&ti);

        // set value
        worksheet.get_cell_mut("D3").set_value(&nm);
        worksheet.get_cell_mut("F3").set_value(id.to_string());

        let merit_1 = sheet.get_value((30, *key));
        worksheet.get_cell_mut("N3").set_value(merit_1);
        //worksheet.get_cell_mut("Q3").set_value(date);

        if args.empty == 1 {
            let merit_1 = sheet.get_value((33, *key));
            worksheet.get_cell_mut("P7").set_value(merit_1);

            let merit_1 = sheet.get_value((34, *key));
            debug!("34: {}", merit_1);
            worksheet.get_cell_mut("R7").set_value(merit_1);
            let merit_1 = sheet.get_value((45, *key));
            worksheet.get_cell_mut("N7").set_value(merit_1);

            let merit_1 = sheet.get_value((35, *key));
            worksheet.get_cell_mut("P8").set_value(merit_1);

            let merit_1 = sheet.get_value((36, *key));
            worksheet.get_cell_mut("R8").set_value(merit_1);
            let merit_1 = sheet.get_value((46, *key));
            worksheet.get_cell_mut("N8").set_value(merit_1);

            let merit_1 = sheet.get_value((37, *key));
            worksheet.get_cell_mut("P9").set_value(merit_1);

            let merit_1 = sheet.get_value((38, *key));
            worksheet.get_cell_mut("R9").set_value(merit_1);
            let merit_1 = sheet.get_value((47, *key));
            worksheet.get_cell_mut("N9").set_value(merit_1);

            let merit_1 = sheet.get_value((39, *key));
            worksheet.get_cell_mut("P10").set_value(merit_1);

            let merit_1 = sheet.get_value((40, *key));
            worksheet.get_cell_mut("R10").set_value(merit_1);
            let merit_1 = sheet.get_value((48, *key));
            worksheet.get_cell_mut("N10").set_value(merit_1);

            let merit_1 = sheet.get_value((41, *key));
            worksheet.get_cell_mut("P11").set_value(merit_1);

            let merit_1 = sheet.get_value((42, *key));
            worksheet.get_cell_mut("R11").set_value(merit_1);
            let merit_1 = sheet.get_value((49, *key));
            worksheet.get_cell_mut("N11").set_value(merit_1);

            let merit_1 = sheet.get_value((43, *key));
            worksheet.get_cell_mut("P12").set_value(merit_1);

            let merit_1 = sheet.get_value((44, *key));
            worksheet.get_cell_mut("R12").set_value(merit_1);
            let merit_1 = sheet.get_value((50, *key));
            worksheet.get_cell_mut("N12").set_value(merit_1);
        }

        // user self

        // writer
        let new_path = if name_set.contains(&nm) {
            format!("{}/{}-{}.xlsx", dir, nm, id)
        } else {
            name_set.insert(nm.clone());
            format!("{}/{}.xlsx", dir, nm)
        };
        info!("> --- {:?}", new_path);
        let path = std::path::Path::new(&new_path);
        let _ = umya_spreadsheet::writer::xlsx::write(&book, path);
    }
    Ok(())
}

#[warn(dead_code)]
fn copy_template_file(
    from: &str,
    id: i64,
    name: &str,
) -> Result<String, Box<dyn std::error::Error>> {
    info!("3---{}", from);
    //
    if !Path::new(RESULT_DIR).exists() {
        fs::create_dir(RESULT_DIR)?;
    }
    let new_path = format!("{}/{}-{}.xlsx", RESULT_DIR, id, name);
    let len = fs::copy(from, &new_path)?;
    //
    info!("copy data len:{}, file:{}", len, new_path);
    Ok(new_path)
}

fn main() {
    tracing_subscriber::fmt::init();

    let args: Cli = Cli::parse();
    let dir = format!("{}-{}{}", RESULT_DIR, args.empty, args.rand);
    if !Path::new(&dir).exists() {
        fs::create_dir(&dir).unwrap();
    }

    info!("args {}!", args.empty);

    match args.rand {
        0 => {
            edit_crate(&args, &dir).unwrap();
        }
        1 => {
            rand_edit_crate(&args, &dir).unwrap();
        }
        _ => {
            warn!("not support command!");
        }
    }
}
